"""
天翼云盘TV版客户端实现

基于tem目录下的设计思路重构的天翼云盘TV版客户端。
"""

import requests
import time
import json
import os
from typing import Dict, List, Optional, Any, Union
from datetime import datetime

from ..base import BaseCloudProvider, CloudFile, UploadResult, DownloadResult, FileType
from .utils import (
    TimeUtils, ClientUtils, CryptoUtils, SignatureUtils, 
    FormatUtils, CacheUtils
)


class TianyiTVProvider(BaseCloudProvider):
    """天翼云盘TV版提供者"""
    
    def __init__(self, config: Dict[str, Any]):
        """
        初始化天翼云盘TV版客户端
        
        Args:
            config: 配置参数，包含access_token等
        """
        super().__init__(config)
        
        self.access_token = config.get('access_token', '')
        self.root_folder_id = config.get('root_folder_id', '-11')
        self.family_id = config.get('family_id', '')
        self.account_type = config.get('type', 'personal')  # personal or family
        
        # 初始化会话
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36',
            'Accept': 'application/json, text/plain, */*',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Accept-Encoding': 'gzip, deflate, br',
            'Connection': 'keep-alive',
        })
        
        # 登录状态
        self._logged_in = False
        self._session_data = {}
        
        # 如果有access_token，设置为已登录状态
        if self.access_token:
            self._logged_in = True
    
    def login(self) -> bool:
        """
        登录天翼云盘TV版
        
        Returns:
            bool: 登录是否成功
        """
        try:
            if self.access_token:
                # 验证token有效性
                if self._validate_token():
                    self._logged_in = True
                    return True
            
            # 如果没有token或token无效，返回False
            return False
            
        except Exception as e:
            print(f"登录失败: {e}")
            return False
    
    def logout(self) -> bool:
        """
        注销登录
        
        Returns:
            bool: 注销是否成功
        """
        try:
            self._logged_in = False
            self._session_data = {}
            self.access_token = ''
            return True
        except Exception as e:
            print(f"注销失败: {e}")
            return False
    
    def list(self, path: str = "/", recursive: bool = False) -> List[CloudFile]:
        """
        列出指定路径下的文件和文件夹
        
        Args:
            path: 路径
            recursive: 是否递归列出子目录
            
        Returns:
            List[CloudFile]: 文件列表
        """
        try:
            if not self._logged_in:
                return []
            
            folder_id = self._path_to_folder_id(path)
            files_data = self._get_files_list(folder_id)
            
            if not files_data:
                return []
            
            files = []
            for file_data in files_data:
                cloud_file = self._convert_to_cloud_file(file_data)
                if cloud_file:
                    files.append(cloud_file)
                    
                    # 如果是递归模式且当前是文件夹，递归获取子文件
                    if recursive and cloud_file.file_type == FileType.FOLDER:
                        sub_path = f"{path.rstrip('/')}/{cloud_file.name}"
                        sub_files = self.list(sub_path, recursive=True)
                        files.extend(sub_files)
            
            return files
            
        except Exception as e:
            print(f"列出文件失败: {e}")
            return []
    
    def upload(self, local_path: str, remote_path: str, 
               rapid_upload: bool = True) -> UploadResult:
        """
        上传文件
        
        Args:
            local_path: 本地文件路径
            remote_path: 远程文件路径
            rapid_upload: 是否使用秒传
            
        Returns:
            UploadResult: 上传结果
        """
        try:
            if not self._logged_in:
                return UploadResult(
                    success=False,
                    message="未登录",
                    file_id="",
                    file_size=0
                )
            
            if not os.path.exists(local_path):
                return UploadResult(
                    success=False,
                    message="本地文件不存在",
                    file_id="",
                    file_size=0
                )
            
            # 获取文件信息
            file_size = os.path.getsize(local_path)
            filename = os.path.basename(local_path)
            
            # 获取父目录ID
            parent_path = os.path.dirname(remote_path)
            parent_id = self._path_to_folder_id(parent_path)
            
            # 尝试秒传
            if rapid_upload:
                file_md5 = self._calculate_file_md5(local_path)
                rapid_result = self._try_rapid_upload(filename, file_size, file_md5, parent_id)
                if rapid_result:
                    return UploadResult(
                        success=True,
                        message="秒传成功",
                        file_id=rapid_result,
                        file_size=file_size
                    )
            
            # 普通上传
            file_id = self._normal_upload(local_path, filename, parent_id)
            if file_id:
                return UploadResult(
                    success=True,
                    message="上传成功",
                    file_id=file_id,
                    file_size=file_size
                )
            else:
                return UploadResult(
                    success=False,
                    message="上传失败",
                    file_id="",
                    file_size=0
                )
                
        except Exception as e:
            return UploadResult(
                success=False,
                message=f"上传失败: {e}",
                file_id="",
                file_size=0
            )
    
    def download(self, remote_path: str, local_path: str) -> DownloadResult:
        """
        下载文件
        
        Args:
            remote_path: 远程文件路径
            local_path: 本地保存路径
            
        Returns:
            DownloadResult: 下载结果
        """
        try:
            if not self._logged_in:
                return DownloadResult(
                    success=False,
                    message="未登录",
                    file_size=0,
                    download_time=0
                )
            
            # 获取下载链接
            download_url = self.get_download_url(remote_path)
            if not download_url:
                return DownloadResult(
                    success=False,
                    message="获取下载链接失败",
                    file_size=0,
                    download_time=0
                )
            
            # 下载文件
            start_time = time.time()
            response = self.session.get(download_url, stream=True)
            response.raise_for_status()
            
            # 确保目录存在
            os.makedirs(os.path.dirname(local_path), exist_ok=True)
            
            file_size = 0
            with open(local_path, 'wb') as f:
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:
                        f.write(chunk)
                        file_size += len(chunk)
            
            download_time = time.time() - start_time
            
            return DownloadResult(
                success=True,
                message="下载成功",
                file_size=file_size,
                download_time=download_time
            )
            
        except Exception as e:
            return DownloadResult(
                success=False,
                message=f"下载失败: {e}",
                file_size=0,
                download_time=0
            )
    
    def delete(self, remote_path: str) -> bool:
        """
        删除文件或文件夹
        
        Args:
            remote_path: 远程路径
            
        Returns:
            bool: 删除是否成功
        """
        try:
            if not self._logged_in:
                return False
            
            # 获取文件信息
            file_info = self.get_file_info(remote_path)
            if not file_info:
                return False
            
            # 删除文件
            url = "https://api.cloud.189.cn/open/file/deleteFile.action"
            params = {
                'fileId': file_info.file_id,
                'access_token': self.access_token
            }
            
            response = self.session.post(url, data=params)
            result = response.json()
            
            return result.get('success', False)
            
        except Exception as e:
            print(f"删除失败: {e}")
            return False
    
    def mkdir(self, path: str) -> bool:
        """
        创建文件夹
        
        Args:
            path: 文件夹路径
            
        Returns:
            bool: 创建是否成功
        """
        try:
            if not self._logged_in:
                return False
            
            # 获取父目录ID
            parent_path = os.path.dirname(path)
            parent_id = self._path_to_folder_id(parent_path)
            folder_name = os.path.basename(path)
            
            # 创建文件夹
            url = "https://api.cloud.189.cn/open/file/createFolder.action"
            params = {
                'parentFolderId': parent_id,
                'folderName': folder_name,
                'access_token': self.access_token
            }
            
            response = self.session.post(url, data=params)
            result = response.json()
            
            return result.get('success', False)
            
        except Exception as e:
            print(f"创建文件夹失败: {e}")
            return False
    
    def move(self, src_path: str, dst_path: str) -> bool:
        """
        移动文件或文件夹
        
        Args:
            src_path: 源路径
            dst_path: 目标路径
            
        Returns:
            bool: 移动是否成功
        """
        # TV版暂不支持移动操作
        return False
    
    def copy(self, src_path: str, dst_path: str) -> bool:
        """
        复制文件或文件夹
        
        Args:
            src_path: 源路径
            dst_path: 目标路径
            
        Returns:
            bool: 复制是否成功
        """
        # TV版暂不支持复制操作
        return False
    
    def rename(self, src_path: str, new_name: str) -> bool:
        """
        重命名文件或文件夹
        
        Args:
            src_path: 源路径
            new_name: 新名称
            
        Returns:
            bool: 重命名是否成功
        """
        try:
            if not self._logged_in:
                return False
            
            # 获取文件信息
            file_info = self.get_file_info(src_path)
            if not file_info:
                return False
            
            # 重命名
            url = "https://api.cloud.189.cn/open/file/renameFile.action"
            params = {
                'fileId': file_info.file_id,
                'fileName': new_name,
                'access_token': self.access_token
            }
            
            response = self.session.post(url, data=params)
            result = response.json()
            
            return result.get('success', False)
            
        except Exception as e:
            print(f"重命名失败: {e}")
            return False
    
    def get_file_info(self, path: str) -> Optional[CloudFile]:
        """
        获取文件信息
        
        Args:
            path: 文件路径
            
        Returns:
            Optional[CloudFile]: 文件信息
        """
        try:
            if not self._logged_in:
                return None
            
            # 获取父目录文件列表
            parent_path = os.path.dirname(path)
            filename = os.path.basename(path)
            
            files = self.list(parent_path)
            for file in files:
                if file.name == filename:
                    return file
            
            return None
            
        except Exception as e:
            print(f"获取文件信息失败: {e}")
            return None
    
    def get_download_url(self, path: str) -> Optional[str]:
        """
        获取文件下载链接
        
        Args:
            path: 文件路径
            
        Returns:
            Optional[str]: 下载链接
        """
        try:
            if not self._logged_in:
                return None
            
            # 获取文件信息
            file_info = self.get_file_info(path)
            if not file_info or file_info.file_type == FileType.FOLDER:
                return None
            
            # 获取下载链接
            url = "https://api.cloud.189.cn/open/file/getFileDownloadUrl.action"
            params = {
                'fileId': file_info.file_id,
                'access_token': self.access_token
            }
            
            response = self.session.get(url, params=params)
            result = response.json()
            
            if result.get('success'):
                return result.get('fileDownloadUrl')
            
            return None
            
        except Exception as e:
            print(f"获取下载链接失败: {e}")
            return None
    
    def save_session(self, path: str) -> bool:
        """
        保存会话信息
        
        Args:
            path: 保存路径
            
        Returns:
            bool: 保存是否成功
        """
        try:
            session_data = {
                'access_token': self.access_token,
                'logged_in': self._logged_in,
                'session_data': self._session_data
            }
            
            with open(path, 'w', encoding='utf-8') as f:
                json.dump(session_data, f, ensure_ascii=False, indent=2)
            
            return True
            
        except Exception as e:
            print(f"保存会话失败: {e}")
            return False
    
    def load_session(self, path: str) -> bool:
        """
        加载会话信息
        
        Args:
            path: 会话文件路径
            
        Returns:
            bool: 加载是否成功
        """
        try:
            if not os.path.exists(path):
                return False
            
            with open(path, 'r', encoding='utf-8') as f:
                session_data = json.load(f)
            
            self.access_token = session_data.get('access_token', '')
            self._logged_in = session_data.get('logged_in', False)
            self._session_data = session_data.get('session_data', {})
            
            # 验证会话有效性
            if self._logged_in and self.access_token:
                return self._validate_token()
            
            return False
            
        except Exception as e:
            print(f"加载会话失败: {e}")
            return False
    
    def is_rapid_upload_supported(self) -> bool:
        """
        检查是否支持秒传
        
        Returns:
            bool: 是否支持秒传
        """
        return True
    
    def _validate_token(self) -> bool:
        """
        验证token有效性
        
        Returns:
            bool: token是否有效
        """
        try:
            url = "https://api.cloud.189.cn/open/user/getUserInfo.action"
            params = {'access_token': self.access_token}
            
            response = self.session.get(url, params=params)
            result = response.json()
            
            return result.get('success', False)
            
        except Exception:
            return False
    
    def _path_to_folder_id(self, path: str) -> str:
        """
        将路径转换为文件夹ID
        
        Args:
            path: 路径
            
        Returns:
            str: 文件夹ID
        """
        if path == "/" or path == "":
            return self.root_folder_id
        
        # 简化实现，实际应该递归查找
        return self.root_folder_id
    
    def _get_files_list(self, folder_id: str) -> Optional[List[Dict[str, Any]]]:
        """
        获取文件列表
        
        Args:
            folder_id: 文件夹ID
            
        Returns:
            Optional[List[Dict[str, Any]]]: 文件列表
        """
        try:
            url = "https://api.cloud.189.cn/open/file/listFiles.action"
            params = {
                'folderId': folder_id,
                'access_token': self.access_token
            }
            
            response = self.session.get(url, params=params)
            result = response.json()
            
            if result.get('success'):
                return result.get('fileList', [])
            
            return None
            
        except Exception as e:
            print(f"获取文件列表失败: {e}")
            return None
    
    def _convert_to_cloud_file(self, file_data: Dict[str, Any]) -> Optional[CloudFile]:
        """
        转换为CloudFile对象
        
        Args:
            file_data: 文件数据
            
        Returns:
            Optional[CloudFile]: CloudFile对象
        """
        try:
            file_type = FileType.FOLDER if file_data.get('isFolder') else FileType.FILE
            
            return CloudFile(
                name=file_data.get('fileName', ''),
                path=file_data.get('filePath', ''),
                file_id=str(file_data.get('fileId', '')),
                size=int(file_data.get('fileSize', 0)),
                file_type=file_type,
                created_time=FormatUtils.format_time(str(file_data.get('createTime', ''))),
                modified_time=FormatUtils.format_time(str(file_data.get('lastOpTime', ''))),
                md5=file_data.get('md5', ''),
                download_url=file_data.get('downloadUrl', '')
            )
            
        except Exception as e:
            print(f"转换文件对象失败: {e}")
            return None
    
    def _calculate_file_md5(self, file_path: str) -> str:
        """
        计算文件MD5
        
        Args:
            file_path: 文件路径
            
        Returns:
            str: MD5值
        """
        import hashlib
        
        md5_hash = hashlib.md5()
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                md5_hash.update(chunk)
        return md5_hash.hexdigest()
    
    def _try_rapid_upload(self, filename: str, file_size: int, file_md5: str, parent_id: str) -> Optional[str]:
        """
        尝试秒传
        
        Args:
            filename: 文件名
            file_size: 文件大小
            file_md5: 文件MD5
            parent_id: 父目录ID
            
        Returns:
            Optional[str]: 文件ID（成功时）
        """
        # TV版暂不支持秒传
        return None
    
    def _normal_upload(self, local_path: str, filename: str, parent_id: str) -> Optional[str]:
        """
        普通上传
        
        Args:
            local_path: 本地文件路径
            filename: 文件名
            parent_id: 父目录ID
            
        Returns:
            Optional[str]: 文件ID（成功时）
        """
        # TV版暂不支持普通上传
        return None